package com.functest.orm

import com.functest.framework.BaseFunctionalTest
import org.testng.annotations.Test

/**
 * Created with IntelliJ IDEA.
 * User: KovalevAS
 * Date: 28.06.13
 * Time: 16:16
 * To change this template use File | Settings | File Templates.
 */
class ConditionTest extends BaseFunctionalTest {


    @Test
    void Condtion_buildSql_singleColumnField() {
        def mapper = TestData.marks_table_multi_column_mapper
        def field = 'id'
        def field_in_db = mapper.getField(mapper.keyField).from.first()

        def testingClosure = {
            def val, ConditionOp op ->
                Condition condition = Condition.of(field, op, val)

                def evaluatedVal = (val instanceof Closure) ? val() : val

                def opBuildRes = op.buildSql(evaluatedVal)
                def expectedRes = ' "' + mapper.tableName + '".' + '"' + field_in_db + '"' + opBuildRes

                logger.info "Condition build result: '${condition.buildSql(mapper)}'"
                logger.info "test build result: '$expectedRes'"

                assert (condition.buildSql(mapper) as String) == (expectedRes as String)
        }

        asStep('Positive:ConditionOps except for IN and NOT_IN') {
            [
                    {
                        int sum = 0
                        (1..6).each {
                            sum += it
                        }
                        sum
                    },
                    "${System.currentTimeMillis()}" as GString,
                    '345',
                    15,
                    null
            ].each { def val ->
                (ConditionOp.values() - [ConditionOp.IN, ConditionOp.NOT_IN]).each { ConditionOp op ->
                    def applicable = !([ConditionOp.LIKE, ConditionOp.NOT_LIKE].contains(op) && !(val instanceof String || val instanceof GString))
                    applicable &= !([ConditionOp.BTEQ, ConditionOp.BTNEQ, ConditionOp.BTANY].contains(op) && !(val instanceof Number))
                    applicable &= !(val == null && ![ConditionOp.IS_NULL, ConditionOp.IS_NOT_NULL].contains(op))
                    if (applicable) testingClosure(val, op)
                }
            }
        }

        asStep('Positive: IN and NOT_IN') {
            [[1, 2, '45'], ['45', '98', "${2 + 2}"], [], [Long.MAX_VALUE], [null, null, null]].each { def val ->
                [ConditionOp.IN, ConditionOp.NOT_IN].each { testingClosure(val, it) }
            }
        }

        asStep('Negative: IN and NOT_IN does not support Scalars') {
            [1, '33', null].each { def val ->
                [ConditionOp.IN, ConditionOp.NOT_IN].each {
                    Exception ex = null
                    try {
                        testingClosure(val, it)
                    } catch (IllegalArgumentException e) {
                        ex = e
                    }
                    assert ex
                }
            }
        }
    }


    @Test
    void Condition_buildSql() {
        def mapper = TestData.marks_table_multi_column_mapper
        def field = 'id'

        asStep('Multicolumn field') {
            field = 'average'
            def value = '353'

            ConditionOp.values().each {
                def op ->
                    def condition = Condition.of(field, op, value)

                    Exception ex = null
                    try {
                        def query = condition.buildSql(mapper)
//                        assert query.contains('first') && query.contains('second') && query.contains('third')
                        logger.debug "Op is: $op, value is $value => Query is: $query"
                    } catch (UnsupportedOperationException e) {
                        ex = e
                        logger.debug(ex.message)
                        assert ex.message.contains('operator is not compatible')
                    }
                    assert ex != null || (op in [ConditionOp.EQ, ConditionOp.NEQ])
            }
        }

    }

}

/*
        field(
        "isin",
        "isin_id",
        {
            Field f, Map row ->
                AnonymousFutures.provider.getTradingCodeByIsin(row[f.from.last()] as Integer)
        },
        {
            Field f, Object value ->
                [(f.from[0]): AnonymousFutures.provider.getIsinByTradingCode(value as String)]
        }
        )
*/